﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SqlString.cs" company="SmartPlan">
//   SmartPlan 2011
// </copyright>
// <summary>
//   The sql string.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace DbDiff.Common.Scripting
{
    using System;
    using System.Text;

    /// <summary>
    /// The sql string.
    /// </summary>
    public class SqlString 
    {
        // Not daily WTF :) different type of databases oracle,mysql or db2 it can be change
        // so we have to move out this for a new type of project (plugin) 
        // for example MssqlScripterPlugin or OracleScripterPlugin, Db2ScripterPlugin etc

        /// <summary>
        /// The cr lf.
        /// </summary>
        public const string CrLf = "\r\n";

        /// <summary>
        /// The cr.
        /// </summary>
        public const string Cr = "\r";

        /// <summary>
        /// The lf.
        /// </summary>
        public const string Lf = "\n";

        /// <summary>
        /// The tab.
        /// </summary>
        public const string Tab = "\t";

        /// <summary>
        /// The space.
        /// </summary>
        public const string Space = " ";

        /// <summary>
        /// The comma.
        /// </summary>
        public const string Comma = ",";
        #region command constraints

        /// <summary>
        /// The sys name.
        /// </summary>
        internal const string SysName ="sysname";

        /// <summary>
        /// The command terminator.
        /// </summary>
        internal const string CommandTerminator="GO";

        /// <summary>
        /// The cmd not for replication.
        /// </summary>
        internal const string cmdNotForReplication="NOT FOR REPLICATION";

        /// <summary>
        /// The cmd create.
        /// </summary>
        internal const string cmdCreate="CREATE";

        /// <summary>
        /// The cmd unique.
        /// </summary>
        internal const string cmdUnique="UNIQUE";

        /// <summary>
        /// The cmd desc.
        /// </summary>
        internal const string cmdDesc="DESC";

        /// <summary>
        /// The cmd index.
        /// </summary>
        internal const string cmdIndex="INDEX";

        /// <summary>
        /// The cmd clustered.
        /// </summary>
        internal const string cmdClustered="CLUSTERED";

        /// <summary>
        /// The cmd primary.
        /// </summary>
        internal const string cmdPrimary="PRIMARY KEY";

        /// <summary>
        /// The cmd procerure.
        /// </summary>
        internal const string cmdProcerure="PROCEDURE";

        /// <summary>
        /// The cmd pad index.
        /// </summary>
        internal const string cmdPadIndex="PAD_INDEX";

        /// <summary>
        /// The cmd fill factor.
        /// </summary>
        internal const string cmdFillFactor="FILLFACTOR";

        /// <summary>
        /// The cmd ignore dup key.
        /// </summary>
        internal const string cmdIgnoreDupKey="IGNORE_DUP_KEY";

        /// <summary>
        /// The cmd no re compute.
        /// </summary>
        internal const string cmdNoReCompute="STATISTICS_NORECOMPUTE";

        /// <summary>
        /// The cmd on.
        /// </summary>
        internal const string cmdOn="ON";

        /// <summary>
        /// The cmd off
        /// </summary>
        internal const string cmdOff = "OFF";

        /// <summary>
        /// The cmd constraint.
        /// </summary>
        internal const string cmdConstraint="CONSTRAINT";

        /// <summary>
        /// The cmd alter.
        /// </summary>
        internal const string cmdAlter="ALTER";

        /// <summary>
        /// The cmd table.
        /// </summary>
        internal const string cmdTable="TABLE";

        /// <summary>
        /// The cmd foreign.
        /// </summary>
        internal const string cmdForeign="FOREIGN KEY";

        /// <summary>
        /// The cmd with.
        /// </summary>
        internal const string cmdWith="WITH";

        /// <summary>
        /// The cmd check.
        /// </summary>
        internal const string cmdCheck="CHECK";

        /// <summary>
        /// The cmd check with no check add check.
        /// </summary>
        internal const string cmdCheckWithNoCheckAddCheck="WITH NOCHECK ADD CHECK";

        /// <summary>
        /// The cmd add with no check add constraint.
        /// </summary>
        internal const string cmdAddWithNoCheckAddConstraint="ADD WITH NOCHECK ADD CONSTRAINT";

        /// <summary>
        /// The cmd references.
        /// </summary>
        internal const string cmdReferences="REFERENCES";

        /// <summary>
        /// The cmd on delete.
        /// </summary>
        internal const string cmdOnDelete="ON DELETE";

        /// <summary>
        /// The cmd on update.
        /// </summary>
        internal const string cmdOnUpdate="ON UPDATE";

        /// <summary>
        /// The cmd cascade.
        /// </summary>
        internal const string cmdCascade="CASCADE";

        /// <summary>
        /// The cmd no action.
        /// </summary>
        internal const string cmdNoAction="NO ACTION";

        /// <summary>
        /// The cmd add.
        /// </summary>
        internal const string cmdAdd="ADD";

        /// <summary>
        /// The cmd no check.
        /// </summary>
        internal const string cmdNoCheck="NO CHECK";

        /// <summary>
        /// The cmd with no check.
        /// </summary>
        internal const string cmdWithNoCheck = "WITH NO CHECK";

        /// <summary>
        /// The cmd drop.
        /// </summary>
        internal const string cmdDrop="DROP";

        /// <summary>
        /// The cmd varchar max.
        /// </summary>
        internal const string cmdVarcharMax="max";

        /// <summary>
        /// The cmd view.
        /// </summary>
        internal const string cmdView = "VIEW";

        /// <summary>
        /// The cmd function.
        /// </summary>
        internal const string cmdFunction = "FUNCTION";

        /// <summary>
        /// The cmd trigger.
        /// </summary>
        internal const string cmdTrigger = "TRIGGER";

        #endregion

        /// <summary>
        /// The command builder
        /// </summary>
        protected StringBuilder cmd = new StringBuilder(string.Empty);


        /// <summary>
        /// Initializes a new instance of the <see cref="SqlString"/> class.
        /// </summary>
        public SqlString()
        {
            
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SqlString"/> class.
        /// </summary>
        /// <param name="defaultString">
        /// The default string.
        /// </param>
        public SqlString(string defaultString)
        {
            this.cmd.Append(defaultString);
        }

        /// <summary>
        /// The sql format.
        /// </summary>
        /// <param name="name">
        /// The object name.
        /// </param>
        /// <returns>
        /// The formatted sql string
        /// </returns>
        public static string QuoteName(string name)
        {
            return string.Format("[{0}]", name);
        }

        /// <summary>
        /// The sql format.
        /// </summary>
        /// <param name="schema">
        /// The schema name.
        /// </param>
        /// <param name="name">
        /// The object name.
        /// </param>
        /// <returns>
        /// The formatted string
        /// </returns>
        public static string QuoteName(string schema, string name)
        {
            return string.Format("[{0}].[{1}]", schema, name);
        }

        /// <summary>
        /// The add row.
        /// </summary>
        public void AddRow()
        {
            this.cmd.Append(CrLf);
        }

        /// <summary>
        /// The add row.
        /// </summary>
        /// <param name="s">
        /// The s.
        /// </param>
        public void AddRow(string s)
        {
            this.cmd.Append(s + CrLf);
        }

        /// <summary>
        /// The add row with comma.
        /// </summary>
        public void AddRowWithComma()
        {
            this.cmd.Append(Comma + CrLf);
        }

        /// <summary>
        /// The add row with tab and new line.
        /// </summary>
        /// <param name="s">
        /// The s.
        /// </param>
        public void AddRowWithTabAndNewLine(string s)
        {
            this.cmd.Append(Tab + s + CrLf);
        }

        /// <summary>
        /// The add row with tab space comma new line.
        /// </summary>
        /// <param name="s">
        /// The s.
        /// </param>
        public void AddRowWithTabSpaceCommaNewLine(string s)
        {
            this.cmd.Append(Tab + s + Space + Comma + CrLf);
        }

        /// <summary>
        /// The add command terminator.
        /// </summary>
        /// <param name="s">
        /// The s.
        /// </param>
        public void AddCommandTerminator(string s)
        {
            this.cmd.Append(s + CrLf + CommandTerminator + CrLf);
        }

        /// <summary>
        /// The add element.
        /// </summary>
        /// <param name="row">
        /// The row.
        /// </param>
        /// <param name="isTabBefore">
        /// The is tab before.
        /// </param>
        /// <param name="isSpaceAfter">
        /// The is space after.
        /// </param>
        public void AddElement(string row, bool isTabBefore, bool isSpaceAfter)
        {
            if (row.Length != 0)
            {
                if (isTabBefore)
                {
                    this.cmd.Append(Tab);
                }

                this.cmd.Append(row);

                if (isSpaceAfter)
                {
                    this.cmd.Append(Space);
                }
            }
        }

        /// <summary>
        /// The add sql string.
        /// </summary>
        /// <param name="sqlString">
        /// The sql string.
        /// </param>
        public void AddSqlString(SqlString sqlString)
        {
            this.cmd.Append(sqlString.cmd.ToString());
        }

        /// <summary>
        /// The add string.
        /// </summary>
        /// <param name="s">
        /// The s.
        /// </param>
        public void AddString(string s)
        {
            this.cmd.Append(s);
        }

        /// <summary>
        /// The to string.
        /// </summary>
        /// <returns>
        /// The to string.
        /// </returns>
        public override string ToString()
        {
            return this.cmd.ToString();
        }

        /// <summary>
        /// The clear.
        /// </summary>
        public void Clear()
        {
            this.cmd = null;
            this.cmd = new StringBuilder(string.Empty);
        }

        /// <summary>
        /// The remove to last cr lf.
        /// </summary>
        public void RemoveToLastCrLf()
        {
            // this.cmd = new StringBuilder(this.cmd.ToString().TrimEnd('\r', '\n'));
            // return;

            char c = Convert.ToChar(Cr);
            int i = this.cmd.Length - 1;
            int j = 1;

            do
            {
                if (i < 0)
                {
                    break;
                }
                
                if (this.cmd[i] == c)
                {
                    break;
                }

                i--;
                j++;
            } 
            while (true);

            if (i > 0)
            {
                this.cmd = this.cmd.Remove(i, j);
            }
        }
    }
}
